#include "Socket.h"
#include "Server.h"
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <string>
#include <cjson/cJSON.h>
#include <vector>
#include <pthread.h>
#include <cjson/cJSON.h>
#include "../../dataParser/include/dataParser.h"
#include <map>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <time.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/wait.h>

using namespace std;

typedef struct MyClientSocketList
{
    int cli_skf;
    int current;  //记录当前共享内存id
    int previous; //记录前一个共享内存id
    int next;     //记录下一共享内存id
} MyClientSocketList;

map<string, string> username_password = {
    {"wzk", "123456"},
    {"db", "123456"},
    {"zjw", "123456"}};

Server server(SOCK_STREAM, 8848, (char *)"127.0.0.1");

int shmid = -1;          //共享空间描述符
MyClientSocketList *shm; //共享空间首地址

void *mainThread(void *p_cli_skf);
int login(const int &cli_skf);
void logout(const int &cli_skf);


int main(int argc, char const *argv[])
{
    server.startServer();

    //创建共享内存
    shmid = shmget((key_t)1234, sizeof(MyClientSocketList), 0666 | IPC_CREAT);
    if (shmid == -1)
    {
        fprintf(stderr, "shmget failed\n");
        exit(EXIT_FAILURE);
    }
    shm = (MyClientSocketList*)shmat(shmid, NULL, 0);
    //初始化共享内存
    memset(shm, 0, sizeof(MyClientSocketList));
    shm->cli_skf = -1;
    shm->next = -1;
    shm->previous = -1;
    shm->current = shmid;

    while (true)
    {
        struct sockaddr_in cli_addr;
        socklen_t len = sizeof(cli_addr);
        int cli_skf = server.acceptConnection((struct sockaddr *)&cli_addr, len);
        MyClientSocketList *i = shm;
        cout << i << endl;
        cout << "hello world" << i->next << endl;
        while (i->next != -1)
        {
            i = (MyClientSocketList *)shmat(i->next, NULL, 0);
        }
        i->next = shmget(0, sizeof(MyClientSocketList), IPC_CREAT | 0666);
        MyClientSocketList *t = (MyClientSocketList *)shmat(i->next, NULL, 0);
        t->cli_skf = cli_skf;
        t->current = i->next;
        t->previous = i->current;
        t->next = -1;

        pthread_t recv_tid;
        pthread_create(&recv_tid, NULL,
                       mainThread, &cli_skf);
        perror("pthread_create");
    }
    cout << "closed\n";
    close(server.ser_skf);

    // 删除共享内存
    if (shmctl(shmid, IPC_RMID, 0) == -1)
    {
        fprintf(stderr, "shmctl(IPC_RMID) failed\n");
        exit(EXIT_FAILURE);
    }
    return 0;
}

void *mainThread(void *p_cli_skf)
{
    int cli_skf = *((int *)p_cli_skf);
    printf("child process: %d created.\n", getpid());
    printf("cli_skf = %d\n", cli_skf);

    int err = login(cli_skf);

    if (err == 0)
    {
        server.sendMSG(cli_skf, (char *)"success", 7);
    }
    else
    {
        server.sendMSG(cli_skf, (char *)"fail", 4);
        logout(cli_skf);
        return NULL;
    }

    while (true)
    {
        if (server.receiveMSG(cli_skf, 1024) > 0)
        {
            cout << server.data_ << endl;
            for (MyClientSocketList *i = shm; i->next != -1;)
            {
                i = (MyClientSocketList *)shmat(i->next, NULL, 0);
                if (i->cli_skf != cli_skf)
                {
                    if (server.sendMSG(i->cli_skf, server.data_, strlen(server.data_)) == -1)
                    {
                        cout << "send error: " << i->cli_skf << endl;
                    }
                }
            }
        }
        else
        {
            logout(cli_skf);
            break;
        }
    }
    cout << "finished" << endl;
    return NULL;
}

int login(const int &cli_skf)
{
    if (server.receiveMSG(cli_skf, 1024) > 0)
    {
        cJSON *json = cJSON_Parse(server.data_);
        char *username = new char[1024];
        char *password = new char[1024];
        parseLoginInfo(json, username, password);
        auto iter = username_password.find(username);
        if (iter != username_password.end())
        {
            if ((*iter).second == string(password))
            {
                return 0;
            }
        }
    }
    return -1;
}

void logout(const int &cli_skf)
{

    for (MyClientSocketList *i = shm; i->next != -1;)
    {
        i = (MyClientSocketList *)shmat(i->next, NULL, 0);
        if (i->cli_skf == cli_skf)
        {
            MyClientSocketList *pre = (MyClientSocketList *)shmat(i->previous, NULL, 0);
            pre->next = i->next;

            if (i->next != -1)
            {
                MyClientSocketList *nxt = (MyClientSocketList *)shmat(i->next, NULL, 0);
                nxt->previous = i->previous;
            }

            int curr = i->current;
            shmdt(i);
            shmctl(curr, IPC_RMID, NULL);
            break;
        }
    }
    cout << "close socket: " << cli_skf << endl;
    close(cli_skf);
}

